package com.homedo.microservice.open.service.gateway.zuul.poller;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.homedo.common.util.Detect;
import com.homedo.microservice.open.service.gateway.bean.enums.FilterTypeEnum;
import com.homedo.microservice.open.service.gateway.bean.enums.forzuulfilter.ProgressEnum4ZuulFilter;
import com.homedo.microservice.open.service.gateway.bean.enums.forzuulfilter.StatusEnum4ZuulFilter;
import com.homedo.microservice.open.service.gateway.bean.po.ZuulFilter;
import com.homedo.microservice.open.service.gateway.persistence.dao.ZuulFilterDao;
import com.homedo.microservice.open.service.gateway.util.ApplicationContextUtil;
import com.homedo.microservice.open.service.gateway.zuul.conf.ZuulCommonConf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * 从数据库拉取过滤器
 */
public class ZuulFilterPollerFromDB {
    private ZuulCommonConf zuulCommonConf;
    private ZuulFilterDao zuulFilterDao;

    private static final Logger LOGGER = LoggerFactory.getLogger(ZuulFilterPollerFromDB.class);

    private Map<String, ZuulFilter> runningFilters = Maps.newConcurrentMap();

    private static ZuulFilterPollerFromDB instance = null;
    private volatile boolean running = true;

    private Thread checherThread = new Thread("ZuulFilterPollerFromDB") {


        public void run() {
            while (running) {

                try {
                    if (!zuulCommonConf.getZuulFilterPollerEnabled().get()) {
                        continue;
                    }

                    List<ProgressEnum4ZuulFilter> progresses = Lists.newArrayList(ProgressEnum4ZuulFilter.PUBLISHED);
                    if (zuulCommonConf.getZuulUseCanaryFilters().get()) {
                        progresses.add(ProgressEnum4ZuulFilter.CANARY);
                    }

                    List<ZuulFilter> zuulFilters = zuulFilterDao.getList4Application(zuulCommonConf.getApplicationName(), progresses, Lists.newArrayList(StatusEnum4ZuulFilter.EFFECTIVE));

                    if (!Detect.notEmpty(zuulFilters)) {
                        continue;
                    }

                    for (ZuulFilter innerZuulFilter : zuulFilters) {

                        doFilterCheck(innerZuulFilter);
                    }

                } catch (Throwable t) {
                    LOGGER.error("ZuulFilterPollerFromDB run error!", t);
                } finally {
                    try {
                        sleep(zuulCommonConf.getZuulFilterPollerInterval().get());
                    } catch (InterruptedException e) {
                        LOGGER.error("ZuulFilterPollerFromDB sleep error!", e);
                    }
                }
            }
        }
    };


    private ZuulFilterPollerFromDB() {
        zuulCommonConf = ZuulCommonConf.get();
        zuulFilterDao = ApplicationContextUtil.getApplicationContext().getBean(ZuulFilterDao.class);

        this.checherThread.setDaemon(true);
        this.checherThread.start();
    }

    public static void start() {
        if (instance == null) {
            synchronized (ZuulFilterPollerFromDB.class) {
                if (instance == null) {
                    instance = new ZuulFilterPollerFromDB();
                }
            }
        }
    }

    public static ZuulFilterPollerFromDB getInstance() {
        return instance;
    }

    public static void stop() {
        if (instance != null) {
            instance.running = false;
        }
    }

    private void doFilterCheck(ZuulFilter zuulFilter) throws IOException {
        ZuulFilter existFilter = runningFilters.get(zuulFilter.getFilterId());
        if (existFilter == null || !existFilter.equals(zuulFilter)) {
            writeFilterToDisk(zuulFilter);
            runningFilters.put(zuulFilter.getFilterId(), zuulFilter);
        }
    }


    private void writeFilterToDisk(ZuulFilter zuulFilter) throws IOException {
        String filterType = zuulFilter.getFilterType();

        String path = zuulCommonConf.getZuulFilterCustomPath();

        if (filterType.equals(FilterTypeEnum.POST.getType())) {
            path = zuulCommonConf.getZuulFilterPostPath();
        } else if (filterType.equals(FilterTypeEnum.ROUTE.getType())) {
            path = zuulCommonConf.getZuulFilterRoutePath();
        } else if (filterType.equals(FilterTypeEnum.ERROR.getType())) {
            path = zuulCommonConf.getZuulFilterErrorPath();
        } else if (filterType.equals(FilterTypeEnum.PRE.getType())) {
            path = zuulCommonConf.getZuulFilterPrePath();
        }

        File groovyFile = new File(path, zuulFilter.getFilterName() + ".groovy");

        LOGGER.info("ZuulFilter写入本地磁盘中...:{}--{}--{}", zuulFilter.getFilterId(), zuulFilter.getFilterName(), groovyFile.getPath());

        if (!groovyFile.getParentFile().exists()) {
            groovyFile.getParentFile().mkdirs();
        }
        try (FileWriter fileWriter = new FileWriter(groovyFile);
             BufferedWriter out = new BufferedWriter(fileWriter)) {
            out.write(zuulFilter.getFilterCode());
        }

        LOGGER.info("ZuulFilter写入本地磁盘成功:{}--{}--{}", zuulFilter.getFilterId(), zuulFilter.getFilterName(), groovyFile.getPath());
    }

}
